package com.transaction.manage.service;

import com.transaction.common.base.ResultVo;
import com.transaction.common.util.DataUtil;
import com.transaction.common.util.DateUtil;
import com.transaction.manage.localMapper.FundRelationMapper;
import com.transaction.manage.localMapper.SequenceMapper;
import com.transaction.manage.model.vo.ComboboxVo;
import com.transaction.manage.taMapper.TaMapper;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * 与TA相关的查询，暂时造假数据 TODO
 */
@Service
public class TaService {

    private static Logger LOGGER = LoggerFactory.getLogger(TaService.class);

    @Autowired
    private TaMapper taMapper;

    @Autowired
    private FundRelationMapper fundRelationMapper;

    @Autowired
    private SequenceMapper sequenceMapper;


    /**
     * 查询TA渠道信息的下拉选择信息
     *
     * @return
     */
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public List<ComboboxVo> getTaChannelInfoCombobox() {
        List<ComboboxVo> list = taMapper.selectAgencyCombobox();
        return list;
    }

    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public List<ComboboxVo> getPayTypeCombobox() {
        List<ComboboxVo> list = taMapper.selectCapTypeCombobox();
        return list;
    }

    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public List<ComboboxVo> getSubChannelCodeCombobox(String channelCode) {
        List<ComboboxVo> list = taMapper.selectSubChannelCodeCombobox(channelCode);
        return list;
    }

    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public List<ComboboxVo> getFundCodeCombobox() {
        List<ComboboxVo> list = taMapper.selectFundCodeCombobox();
        return list;
    }

    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public List<ComboboxVo> getFundYieldTypes(String channelCode,String fundCode) {
        List<String> taFundCodeList = fundRelationMapper.selectTaFundCodeList(channelCode,fundCode);
        List<ComboboxVo> list = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(taFundCodeList)){
            list = taMapper.selectFundYieldCombobox(taFundCodeList);
        }
        if(CollectionUtils.isEmpty(list)){
            ComboboxVo o = new ComboboxVo("0","0(默认)");
            list.add(o);
        }
        return list;
    }

    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public List<ComboboxVo> getFundYields(String channelCode,String fundCode) {
        List<String> taFundCodeList = fundRelationMapper.selectTaFundCodeList(channelCode,fundCode);
        List<ComboboxVo> list = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(taFundCodeList)){
            list = taMapper.selectFundYieldsCombobox(taFundCodeList);
        }
        if(CollectionUtils.isEmpty(list)){
            ComboboxVo o = new ComboboxVo("0","0-0-9999999999");
            list.add(o);
        }
        return list;
    }

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public ResultVo openAccount(LinkedHashMap<String, Object> data) {

        //校验数据是否为空
        if(data == null || data.isEmpty()){
            return ResultVo.errorMsg("传入的数据参数不能为空,请检查。");
        }

        String individualOrInstitution = MapUtils.getString(data, "INDIVIDUALORINSTITUTION");
        String certificateType = MapUtils.getString(data, "CERTIFICATETYPE");
        String certificateNo = MapUtils.getString(data, "CERTIFICATENO");
        String investorName = MapUtils.getString(data, "INVESTORNAME");
        //校验4要素是否存在
        if(StringUtils.isEmpty(individualOrInstitution) ||
                StringUtils.isEmpty(certificateType) ||
                StringUtils.isEmpty(certificateNo) ||
                StringUtils.isEmpty(investorName)){
            return ResultVo.errorMsg("客户4要素客户类型、证件类型、证件号码、客户姓名不能为空,请检查。");
        }

        //查看TAaccountId是否有值,有值为修改资料
        String taAccountId = MapUtils.getString(data, "TAACCOUNTID");

        //简单实现
        if(StringUtils.isEmpty(taAccountId)){
            //查询TA是否已开户,已开户直接返回taAccountId
            String fundAcco = taMapper.seletFundAccoBy4Element(individualOrInstitution,certificateType,certificateNo,investorName);
            if(StringUtils.isEmpty(fundAcco)){
                //开户
                taAccountId = generateTaAccountId(individualOrInstitution,certificateType,certificateNo,investorName);
                //账户信息插入库表
                LOGGER.info("通过客户类型:{},证件类型:{},证件号码:{},客户姓名:{},生成的TA投资人基金账号:{}",
                        individualOrInstitution,certificateType,certificateNo,investorName,taAccountId);
                taMapper.insertCustomerInfo(individualOrInstitution,certificateType,certificateNo,investorName,taAccountId);
            }
            else{
                taAccountId = fundAcco;
            }
        }else{
            //修改资料
            int count = taMapper.seletCustomerCountByFundAcco(taAccountId);
            if(count == 0){
                return ResultVo.errorMsg(taAccountId + "基金账号不存在,请检查。");
            }else{
                //修改4要素
                taMapper.updateCustomerInfoBuyFundAcco(individualOrInstitution,certificateType,certificateNo,investorName,taAccountId);
            }
        }
        return ResultVo.ok(taAccountId);
    }

    /**
     * 模拟生成投资人基金账号
     * @param individualOrInstitution 客户类型
     * @param certificateType 证件类型
     * @param certificateNo 证件号码
     * @param investorName 客户姓名
     * @return
     */
    private String generateTaAccountId(String individualOrInstitution, String certificateType,
                                       String certificateNo, String investorName) {
        String input = individualOrInstitution + "@#$%&*"
                + certificateType + "@#$%&*"
                + certificateNo + "@#$%&*"
                + investorName;
        //全部转为对应ASCII码
        StringBuilder builder = new StringBuilder();
        char[] chars = input.toCharArray();
        int length = chars.length;
        for (int i = 0 ; i < length; i++){
            builder.append((int)chars[i]);
        }
        int cd = 150;
        //按15个字符一份分成10份，不够长的补0
        String value = DataUtil.prefixReplenishZero(builder.toString(),cd);
        Integer[] values = new Integer[10];
        int a = 0;
        int j = 0;
        for (int i = 0 ; i < cd; i++){
            if((i+1)%15==0){
                values[j] = a;
                j++;
            }
            a += (value.charAt(i) - '0');
        }
        StringBuilder ret = new StringBuilder("ST");
        for(int k = 0 ;k <values.length; k++){
            ret.append(values[k]%9);
        }
        return ret.toString();
    }

    /**
     * TA交易购买
     * @param request 交易传参
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public ResultVo transBuy(LinkedHashMap<String, Object> request) {

        /**
         * 首先看是首次还是追加,首次需要生成合同,追加只需要插入交易，然后更新合同金额
         */
        Map<String,Object> retMap = new HashMap<>();

        String contractSerialNo = MapUtils.getString(request,"CONTRACTSERIALNO");
        String trustContractId = MapUtils.getString(request,"TRUSTCONTRACTID");

        String fundAcco = MapUtils.getString(request,"FUNDACCO");
        String fundCode = MapUtils.getString(request,"FUNDCODE");
        String isAppend = MapUtils.getString(request,"ISAPPEND");
        String outRequestNo = MapUtils.getString(request,"OUTREQUESTNO");


        BigDecimal balance = new BigDecimal(MapUtils.getString(request,"BALANCE","0"));

        if(BigDecimal.ZERO.compareTo(balance) == 0 ){
            return ResultVo.errorMsg("调用接口【transBuy】失败,请传入购买金额");
        }

        //判断客户存不存在
        int accoCount = taMapper.selectFundAccoIsValid(fundAcco);
        if(accoCount == 0){
            return ResultVo.errorMsg("调用接口【transBuy】失败," + fundAcco + "在TA不存在");
        }
        //判断产品存不存在
        int fundCount = taMapper.selectFundCodeIsValid(fundCode);
        if(fundCount == 0){
            return ResultVo.errorMsg("调用接口【transBuy】失败," + fundCode + "在TA不存在。");
        }

        String businFlg = MapUtils.getString(request,"BUSINFLAG");
        //生成requestNO
        String requestNo = DateUtil.formatDate(new Date(),DateUtil.FORMAT_STR_TIME14) + sequenceMapper.getNextValue("requestNo");
        request.put("REQUESTNO",requestNo);
        request.put("OUTBUSINFLAG",businFlg.equals("1") ? "020" : "022");

        //如果追加标识为1:追加,判断合同是否存在
        if("1".equals(isAppend)){
            if(StringUtils.isEmpty(contractSerialNo) || StringUtils.isEmpty(trustContractId)){
                return ResultVo.errorMsg("调用接口【transBuy】失败,追加交易合同号不能为空。");
            }
            Map<String,Object> contractMap = taMapper.selectContractByContractNo(contractSerialNo,trustContractId);
            if(contractMap == null){
                return ResultVo.errorMsg("调用接口【transBuy】失败,合同号对应的合同不存在。");
            }

            String contractFundAcco = MapUtils.getString(contractMap,"FUNDACCO");
            String contractFundCode = MapUtils.getString(contractMap,"FUNDCODE");

            if(!fundAcco.equals(contractFundAcco)){
                return ResultVo.errorMsg("调用接口【transBuy】失败,该追加合同与传入的客户不匹配。");
            }

            if(!fundCode.equals(contractFundCode)){
                return ResultVo.errorMsg("调用接口【transBuy】失败,该追加合同与传入的产品不匹配。");
            }

            //查询该外部传入流水号是否存在，存在判断其他条件是否一致，一致直接返回
            Map<String,Object> transRequest = taMapper.selectRequestBuyOutRequestNo(outRequestNo);
            if(transRequest != null){
                if(!(fundAcco.equals(MapUtils.getString(transRequest,"FUNDACCO"))
                        && fundCode.equals(MapUtils.getString(transRequest,"FUNDCODE"))
                        && contractSerialNo.equals(MapUtils.getString(transRequest,"CONTRACTSERIALNO"))
                        && balance.compareTo(new BigDecimal(MapUtils.getString(transRequest,"FUNDACCO","0"))) == 0)){
                    return ResultVo.errorMsg("调用接口【transBuy】失败,传入的流申请单编号与已存在的申请单标号一致,单其他参数不同,请检查。");
                }
                contractSerialNo = MapUtils.getString(transRequest,"CONTRACTSERIALNO");
                requestNo = MapUtils.getString(transRequest,"REQUESTNO");
            }else {
                //更新合同总金额
                taMapper.updateTrustContractSumBalance(contractMap, balance);

                //插入交易申请表
                taMapper.insertRequest(request);
            }
            //返回交易的requestNo和内部合同号
            retMap.put("CONTRACTSERIALNO",contractSerialNo);
            retMap.put("TRUSTCONTRACTID",trustContractId);
            retMap.put("REQUESTNO",requestNo);

        }else{

            if(StringUtils.isEmpty(trustContractId)){
                return ResultVo.errorMsg("调用接口【transBuy】失败,交易合同号不能为空。");
            }

            //查询该外部传入流水号是否存在，存在判断其他条件是否一致，一致直接返回
            Map<String,Object> transRequest = taMapper.selectRequestBuyOutRequestNo(outRequestNo);
            if(transRequest != null){
                    if(!(fundAcco.equals(MapUtils.getString(transRequest,"FUNDACCO"))
                    && fundCode.equals(MapUtils.getString(transRequest,"FUNDCODE"))
                    && contractSerialNo.equals(MapUtils.getString(transRequest,"CONTRACTSERIALNO"))
                    && balance.compareTo(new BigDecimal(MapUtils.getString(transRequest,"FUNDACCO","0"))) == 0)){
                        return ResultVo.errorMsg("调用接口【transBuy】失败,传入的流申请单编号与已存在的申请单标号一致,单其他参数不同,请检查。");
                    }
                contractSerialNo = MapUtils.getString(transRequest,"CONTRACTSERIALNO");
                requestNo = MapUtils.getString(transRequest,"REQUESTNO");
            }else{
                contractSerialNo = sequenceMapper.getNextValue("inContract");
                request.put("CONTRACTSERIALNO",contractSerialNo);

                //插入交易申请表
                taMapper.insertRequest(request);

                //插入合同表
                taMapper.insertTrustContract(request);
            }

            retMap.put("CONTRACTSERIALNO",contractSerialNo);
            retMap.put("TRUSTCONTRACTID",trustContractId);
            retMap.put("REQUESTNO",requestNo);
        }

        return ResultVo.ok(retMap);

    }

    /**
     * 交易赎回接口  TODO
     * @param request 交易申请
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public ResultVo transRedeem(LinkedHashMap<String, Object> request) {

        return ResultVo.ok();
    }

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void createTaFundNetValueAndIncome() {
        Random random = new Random();
        List<Map<String,Object>> list = new ArrayList<>();
        //有些产品生成净值,有些生成万份收益和七日年化

        //净值不是每天都更新,用随机数来随机要不要更新
        if(random.nextInt(2) == 1) {//需要更新净值
            List<String> netFundCode = taMapper.selectNetFundCode();
            if (CollectionUtils.isNotEmpty(netFundCode)) {
                netFundCode.forEach(v -> {
                    Map<String, Object> map = new HashMap<>();
                    BigDecimal netValue = new BigDecimal(1);
                    //生成净值差值
                    BigDecimal diff = new BigDecimal(random.nextDouble() / 10).setScale(8, BigDecimal.ROUND_DOWN);
                    if (random.nextInt(2) == 0) {//减去差值
                        netValue = netValue.subtract(diff);
                    } else {
                        netValue = netValue.add(diff);
                    }
                    map.put("FUNDCODE", v);
                    map.put("NETVALUE", netValue);
                    map.put("TOTALNETVALUE", netValue);
                    list.add(map);
                });
            }
        }

        List<String> incomeFundCode = taMapper.selectIncomeFundCode();
        if(CollectionUtils.isNotEmpty(incomeFundCode)){
            incomeFundCode.forEach(v->{
                Map<String,Object> map = new HashMap<>();
                BigDecimal incomeUnit = new BigDecimal(1);
                //生成万份收益差值
                BigDecimal diff = new BigDecimal(random.nextDouble()/10).setScale(5,BigDecimal.ROUND_DOWN);
                if(random.nextInt(2) == 0){//减去差值
                    incomeUnit = incomeUnit.subtract(diff);
                }else{
                    incomeUnit = incomeUnit.add(diff);
                }
                map.put("FUNDCODE",v);
                map.put("INCOMEUNIT",incomeUnit);
                map.put("INCOMERATIO",incomeUnit.multiply(new BigDecimal(365)).divide(new BigDecimal(10000)).setScale(5,BigDecimal.ROUND_DOWN));
                list.add(map);
            });
        }
        //删除并插入表
        taMapper.deleteCrmFundDay();
        taMapper.insertCrmFundDay(list);
    }

    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    public List<Map<String,Object>> getCrmFundDay(String date) {
        return taMapper.getCrmFundDay(date);
    }
}